package com.mask.im.business.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.mask.im.business.common.model.RestResponse;
import com.mask.im.business.model.entity.chat.IMGroupChatDO;
import com.mask.im.business.model.entity.chat.IMGroupChatUserDO;
import com.mask.im.business.model.vo.*;
import com.mask.im.business.mapper.IMGroupChatMapper;
import com.mask.im.business.model.entity.chat.Friendships;
import com.mask.im.business.model.entity.UserInfo;
import com.mask.im.business.common.exception.BusinessException;
import com.mask.im.business.mapper.FriendshipsMapper;
import com.mask.im.business.model.dto.*;
import com.mask.im.business.common.model.PageResult;
import com.mask.im.business.service.*;
import com.mask.im.business.common.util.MaskIMSecurityUtils;
import com.mask.im.business.common.util.PageUtil;
import com.mask.im.business.common.constant.RegisterConstant;
import com.mask.im.business.common.model.IMSendMessage;
import com.mask.token.util.MaskSecurityUtil;
import io.netty.channel.Channel;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import lombok.SneakyThrows;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;

import static com.mask.im.business.common.constant.CommonConstant.*;
import static com.mask.im.business.common.constant.GroupChatConstant.DISBAND;


/**
 * 群组管理
 *
 * @author jian
 */
@Service
public class IMGroupChatServiceImpl extends ServiceImpl<IMGroupChatMapper, IMGroupChatDO> implements IMGroupChatService {

    @Resource
    private IMGroupChatUserService groupChatUserService;

    @Resource
    private IMGroupChatMapper groupChatMapper;

    @Resource
    private UserInfoService userInfoService;

    @Resource
    private ChannelService channelService;

    @Resource
    private FriendshipsMapper friendshipsMapper;

    @Resource
    private LiveChatService liveChatService;

    @Resource
    private IMChatListService chatListService;

    @Override
    public void createGroupChat(GroupChatVO groupChatVO) {
        Long userId = MaskSecurityUtil.getCurrentUserId();
        //校验
        Integer createGroupChatCount = this.baseMapper.selectCount(new LambdaQueryWrapper<IMGroupChatDO>()
                .eq(IMGroupChatDO::getOwnerId, userId));
        WebsiteConfigDTO websiteConfig = liveChatService.getWebsiteConfig();
        if (createGroupChatCount > websiteConfig.getAllowGroupChatCount()) {
            throw new BusinessException("创建群聊数量不能超过" + websiteConfig.getAllowGroupChatCount() + "个");
        }

        buildGroupChatCheck(groupChatVO);
        List<Long> userInfoIds = groupChatVO.getUserInfoIds();
        IMGroupChatDO imGroupChat = IMGroupChatDO.builder()
                .groupAvatar(StringUtils.isBlank(groupChatVO.getAvatar()) ? RegisterConstant.DEFAULT_AVATAR : groupChatVO.getAvatar())
                .groupName(groupChatVO.getGroupName())
                .ownerId(userId)
                .recentTime(new Date())
                .administrator(userId.toString())
                .currentMemberCount(1 + userInfoIds.size()).build();
        this.baseMapper.insert(imGroupChat);

        Long groupChatId = imGroupChat.getId();
        String groupName = imGroupChat.getGroupName();

        List<IMGroupChatUserDO> imGroupChatUsers = new ArrayList<>();
        userInfoIds.add(userId);
        userInfoIds.forEach(uId -> {
            IMGroupChatUserDO imGroupChatUser = new IMGroupChatUserDO();
            imGroupChatUser.setGroupId(groupChatId);
            imGroupChatUser.setGroupRemark(groupName);
            imGroupChatUser.setUserId(uId);
            imGroupChatUser.setMemberStatus(1);
            imGroupChatUser.setLatestSpeakTime(LocalDateTime.now());
            if (channelService.getUserIdChannel(uId.toString()) == null) {
                imGroupChatUser.setIsOnline(0);
            } else {
                imGroupChatUser.setIsOnline(1);
            }
            imGroupChatUser.setIsActive(0);
            imGroupChatUsers.add(imGroupChatUser);
        });
        groupChatUserService.inserBatch(imGroupChatUsers);
        //给每一个全用户创建一个对应的chatList
        chatListService.createGroupChatList(imGroupChat, userInfoIds);
        //TODO::给群内是所有人发通知

    }


    @Override
    public List<FriendshipsDTO> getGroupChat(Long userId) {
        return this.baseMapper.getGroupChat(userId);
    }


    @Override
    public PageResult<GroupMembersDTO> getGroupMembers(Integer chatGroupId) throws ExecutionException, InterruptedException {
        IMGroupChatDO groupChat = this.baseMapper.selectById(chatGroupId);
        if (!groupChat.getStatus().equals(ZERO)) {
            throw new BusinessException("群聊不存在或已解散！");
        }
        CompletableFuture<Integer> count = CompletableFuture.supplyAsync(() -> this.baseMapper.getGroupMembersCount(chatGroupId));
        List<GroupMembersDTO> groupMembers = this.baseMapper.getGroupMembers(chatGroupId, PageUtil.getCurrentPage(), PageUtil.getSize());
        return PageResult.<GroupMembersDTO>builder().data(groupMembers).total(count.get()).code(20000).build();
    }


    @Override
    public RestResponse<Boolean> isGroupLeader(Integer groupChatId) {
        Integer userInfoId = MaskIMSecurityUtils.getUserId();
        IMGroupChatDO groupChat = this.baseMapper.selectById(groupChatId);
        if (groupChat.getOwnerId().equals(userInfoId)) {
            return RestResponse.ok(true);
        }
        return RestResponse.ok(false);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public RestResponse<String> disbandGroupChat(Integer groupChatId) {
        Integer userInfoId = MaskIMSecurityUtils.getUserId();
        IMGroupChatDO imGroupChat = this.baseMapper.selectById(groupChatId);
        if (!imGroupChat.getOwnerId().equals(userInfoId)) {
            throw new BusinessException("您不是群主无法解散群聊");
        }
        List<IMGroupChatUserDO> imGroupChatUsers = groupChatUserService.list(new LambdaQueryWrapper<IMGroupChatUserDO>()
                .select(IMGroupChatUserDO::getUserId)
                .eq(IMGroupChatUserDO::getGroupId, groupChatId));
        imGroupChatUsers.forEach(item -> {
            Channel userIdChannel = channelService.getUserIdChannel(item.getUserId().toString());
            if (userIdChannel != null) {
                IMSendMessage websocketDTO = new IMSendMessage();
                websocketDTO.setCmd(30009);
//                websocketDTO.setMessage(1);//解散群聊标识
                websocketDTO.setData(groupChatId);
                userIdChannel.writeAndFlush(new TextWebSocketFrame(JSON.toJSONString(websocketDTO)));
            }
        });
        imGroupChat.setStatus(DISBAND);
        this.updateById(imGroupChat);
        groupChatUserService.updateStatus(userInfoId, groupChatId);
        return RestResponse.ok("解散成功");
    }

    @Override
    public RestResponse<Boolean> getGroupChatStatus(Integer groupChatId) {
        IMGroupChatDO imGroupChat = this.baseMapper.selectById(groupChatId);
        if (imGroupChat.getStatus().equals(DISBAND)) {
            return RestResponse.ok(false);
        }
        return RestResponse.ok(true);
    }

    @Override
    public RestResponse<String> pullGroupChat(PullChatVO pullChatVO) {
        IMGroupChatDO imGroupChat = this.getById(pullChatVO.getGroupChatId());
        if (Objects.isNull(imGroupChat) || imGroupChat.getStatus().equals(TRUE)) {
            throw new BusinessException("群聊不存在或已解散");
        }
        //判断是否为好友
        StringBuilder friendRemark = new StringBuilder();
        boolean flag = false;
        for (Long friendId : pullChatVO.getFriendIds()) {
            Friendships friendships = friendshipsMapper.selectOne(new LambdaQueryWrapper<Friendships>()
                    .eq(Friendships::getOneUserId, friendId)
                    .eq(Friendships::getTwoUserId, MaskIMSecurityUtils.getUserId()));
            if (friendships == null || !friendships.getIsFriends().equals(IS_FRIEND)) {
                Friendships myFriend = friendshipsMapper.selectOne(new LambdaQueryWrapper<Friendships>()
                        .eq(Friendships::getOneUserId, MaskIMSecurityUtils.getUserId())
                        .eq(Friendships::getTwoUserId, friendId));
                friendRemark.append(friendships == null ? "" : myFriend.getRemark() + " ");
                if (!flag && friendships == null) {
                    flag = true;
                }
            }
        }
        if (friendRemark.toString().isEmpty() && flag) {
            return RestResponse.fail("拉入群聊失败，拉入群聊用户中包含非好友关系的用户");
        }
        if (!friendRemark.toString().isEmpty()) {
            return RestResponse.fail("拉入群聊失败，" + friendRemark.toString().trim()
                    .replaceAll(" ", ",") + " 为非好友关系，请添加其为好友后重新操作");
        }

        IMSendMessage websocketDTO = new IMSendMessage();
        websocketDTO.setCmd(30006);
        List<Long> friendIdList = pullChatVO.getFriendIds();
        friendIdList.forEach(friendId -> {
            IMGroupChatUserDO imGroupChatUser = groupChatUserService.getOne(new LambdaQueryWrapper<IMGroupChatUserDO>()
                    .eq(IMGroupChatUserDO::getGroupId, pullChatVO.getGroupChatId())
                    .eq(IMGroupChatUserDO::getUserId, friendId));
            if (imGroupChatUser != null) {
                if (imGroupChatUser.getMemberStatus().equals(2)) {
                    groupChatUserService.update(new LambdaUpdateWrapper<IMGroupChatUserDO>()
                            .set(IMGroupChatUserDO::getMemberStatus, 1).eq(IMGroupChatUserDO::getId, imGroupChatUser.getId()));
                }
            } else {
                UserInfo userInfo = userInfoService.getById(friendId);
                IMGroupChatUserDO chatUser = IMGroupChatUserDO.builder()
                        .groupId(pullChatVO.getGroupChatId())
                        .userId(friendId)
                        .customNickname(userInfo.getNickName())
                        .isOnline(channelService.getUserIdChannel(friendId.toString()) != null ? 1 : 0)
                        .memberStatus(1)
                        .groupRemark(imGroupChat.getGroupName())
                        .build();
                groupChatUserService.save(chatUser);
                Channel userIdChannel = channelService.getUserIdChannel(friendId.toString());
                //通知其他人刷新好友栏
                if (userIdChannel != null) {
                    userIdChannel.writeAndFlush(new TextWebSocketFrame(JSON.toJSONString(websocketDTO)));
                }
            }
        });
        //通知自己刷新好友栏
        Channel userIdChannel = channelService.getUserIdChannel(MaskIMSecurityUtils.getUserId().toString());
        if (userIdChannel != null) {
            userIdChannel.writeAndFlush(new TextWebSocketFrame(JSON.toJSONString(websocketDTO)));
        }
        return RestResponse.ok();
    }

    @SneakyThrows
    @Override
    public RestResponse<GroupChatDTO> groupChatMessage(Integer chatGroupId) {
        Long userInfoId = MaskSecurityUtil.getCurrentUserId();
        IMGroupChatDO imGroupChatDO = this.baseMapper.selectById(chatGroupId);
        GroupChatDTO groupChatMessageDTO = new GroupChatDTO();
        CompletableFuture<IMGroupChatUserDO> groupChatUserCompletableFuture = CompletableFuture.supplyAsync(() ->
                groupChatUserService.getOne(new LambdaQueryWrapper<IMGroupChatUserDO>()
                        .eq(IMGroupChatUserDO::getGroupId, chatGroupId)
                        .eq(IMGroupChatUserDO::getUserId, userInfoId)
                        .eq(IMGroupChatUserDO::getMemberStatus, TRUE)));
        groupChatMessageDTO.setGroupId(imGroupChatDO.getId());
        groupChatMessageDTO.setGroupName(imGroupChatDO.getGroupName());
        if (groupChatUserCompletableFuture.get() == null) {
            throw new BusinessException("您还未加入该群聊！");
        }
        groupChatMessageDTO.setGroupRemark(groupChatUserCompletableFuture.get().getGroupRemark());
        groupChatMessageDTO.setCustomizeRemark(groupChatUserCompletableFuture.get().getCustomNickname());
        groupChatMessageDTO.setAvatar(imGroupChatDO.getGroupAvatar());
        groupChatMessageDTO.setCreateTime(imGroupChatDO.getCreateTime());
        groupChatMessageDTO.setDisplayName(StringUtils.isNotBlank(groupChatUserCompletableFuture.get().getGroupRemark())? groupChatUserCompletableFuture.get().getGroupRemark():imGroupChatDO.getGroupName());
        //查看所有群成员
        List<IMGroupChatUserDO> chatUserDOList = groupChatUserService.list(new LambdaQueryWrapper<IMGroupChatUserDO>().eq(IMGroupChatUserDO::getGroupId, imGroupChatDO.getId()));
        if (null != chatUserDOList && !chatUserDOList.isEmpty()){
            List<IMGroupChatUserVO> imGroupChatUsers = BeanUtil.copyToList(chatUserDOList, IMGroupChatUserVO.class);
            groupChatMessageDTO.setMembers(imGroupChatUsers);
        }
        return RestResponse.ok(groupChatMessageDTO);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public RestResponse<String> updateGroupChatMessage(GroupChatDTO groupChatMessageDTO) {
        Integer userInfoId = MaskIMSecurityUtils.getUserId();
        IMGroupChatDO imGroupChat = this.baseMapper.selectById(groupChatMessageDTO.getGroupId());
        if (!imGroupChat.getGroupName().equals(groupChatMessageDTO.getGroupName())) {
            if (!imGroupChat.getOwnerId().equals(userInfoId)) {
                throw new BusinessException("非群主不能修改群聊名称！");
            }
            IMGroupChatDO buildIMGroupChat = IMGroupChatDO.builder()
                    .id(groupChatMessageDTO.getGroupId())
                    .groupName(groupChatMessageDTO.getGroupName())
                    .build();
            this.baseMapper.updateById(buildIMGroupChat);
        }
        groupChatUserService.update(new LambdaUpdateWrapper<IMGroupChatUserDO>()
                .set(IMGroupChatUserDO::getCustomNickname, groupChatMessageDTO.getCustomizeRemark())
                .set(IMGroupChatUserDO::getGroupRemark, groupChatMessageDTO.getGroupRemark())
                .eq(IMGroupChatUserDO::getGroupId, groupChatMessageDTO.getGroupId())
                .eq(IMGroupChatUserDO::getUserId, userInfoId));
        return RestResponse.ok();
    }

    @SneakyThrows
    @Override
    public PageResult<GroupChatAdminDTO> groupChatList(ConditionVO conditionVO) {
        CompletableFuture<Integer> completableFuture = CompletableFuture.supplyAsync(() ->
                this.baseMapper.selectGroupChatCount(conditionVO.getKeywords()));
        List<GroupChatAdminDTO> groupChatAdminDTOS =
                this.baseMapper.selectGroupChatList(conditionVO.getKeywords(), PageUtil.getCurrentPage(), PageUtil.getSize());
        return PageResult.<GroupChatAdminDTO>builder()
                .code(200)
                .data(groupChatAdminDTOS)
                .total(completableFuture.get())
                .build();
    }

    @Override
    public RestResponse<String> operateStatus(Long id, Integer status) {
        IMGroupChatDO imGroupChat = new IMGroupChatDO();
        imGroupChat.setId(id);
        imGroupChat.setStatus(status);
        this.baseMapper.updateById(imGroupChat);
        return RestResponse.ok();
    }

    @Override
    public RestResponse<List<IMGroupChatVO>> getGroupList() {
        Long userId = MaskSecurityUtil.getCurrentUserId();
        if (null != userId) {
            List<IMGroupChatVO> groupList = groupChatMapper.getGroupList(userId);
            if (null != groupList && !groupList.isEmpty()) {
                return RestResponse.ok(groupList);
            }
        } else {
            throw new BusinessException("未登录异常!");
        }
        return RestResponse.ok();
    }


    void buildGroupChatCheck(GroupChatVO groupChatVO) {
        if (groupChatVO.getGroupName() == null || groupChatVO.getGroupName().isEmpty()) {
            throw new BusinessException("群名称不能为空哦");
        }
        if (groupChatVO.getUserInfoIds() == null || groupChatVO.getUserInfoIds().size() == 0) {
            throw new BusinessException("创建群聊至少需要用两名成员在内");
        }
    }

}

